S3バケットにJSONファイルをアップロードするCI・CDを作ってみた
スマホアプリで全ユーザに「お知らせ」を表示しようと思い、JSONデータを公開する仕組みを作ってみました。
API(API Gateway + Lambda)を作っても良かったのですが、簡単に済ませるため、S3バケットにJSONファイルを格納して公開することで簡略化しました。 (「クラウド側の仕組みとCI/CDの仕組み」を作ってみたかった)
目次
概要
GitHubリポジトリのJSONファイルを更新すると、CircleCIによってS3バケットのJSONファイルが更新されます。簡略化のためCloudFrontは未使用です。
JSONファイルの仕様
次のJSONファイルをS3バケットに格納します。なお、「お知らせ」の更新頻度は月数回を想定しているため、頻繁なJSONデータ取得はさせない予定です。(この仕組はクライアント側ですが、Period
パラメータを利用する想定)
{ "Message": "お知らせ:xxxxx", "DeadlineTimestamp": 1578636000, "Period": 86400 }
- Message
- 表示するお知らせの本文
- DeadlineTimestamp
- お知らせの有効期限(Unixtime)
- これ以降はお知らせを表示しない
- Period
- データ再取得の期間(Unixtime)
- 前回取得してからこの期間が経過すると、再取得する
リポジトリとブランチ運用
master
ブランチにPushされたら、CircleCIによって開発環境にデプロイします。そのあと、CircleCIのApprove機能で本番環境にデプロイします。
種類 | 名前の例 | 環境 |
---|---|---|
ブランチ | master | 開発環境 → 本番環境 |
CI/CDを構築する
下記を作成していきます。
- Python仮想環境を作成
- Makefileを作成
- S3バケットを作成
- IAMユーザとIAMロールを作成(CircleCI用)
- IAMロールのARNを取得
- IAMユーザのアクセスキーを取得
- 単体テスト用のファイルを作成
- AssumeRole用のスクリプトを作成
- CircleCIの設定ファイルを作成
- CircleCIの設定
なお、IAMユーザやIAMロールの詳細は下記をご覧ください。
Python仮想環境を作成
次のコマンドでPythonの仮想環境を作成します。
$ pipenv install --python 3.7.2
続いて、次のコマンドで必要なライブラリをPython仮想環境に導入します。
$ pipenv install awscli $ pipenv install pytest
Makefileを作成
次のMakefileを作成します。
S3バケット & IAMユーザ & IAMロールを作成
次のCloudFormationテンプレートをprepare.yaml
として作成します。sts:ExternalId
には任意の値を設定します。これはCircelCIの環境変数に設定します。
続いてデプロイします。
$ ENV=dev make prepare $ ENV=prod make prepare
IAMロールのARNを取得
次のコマンドを実行し、作成したIAMロールのARNを取得します。これはAssumeRoleするために必要なのでメモしておき、CircelCIの環境変数に設定します。
$ ENV=dev make describe-prepare $ ENV=prod make describe-prepare
IAMユーザのアクセスキーを取得
IAMユーザのアクセスキーを取得します。これはCircleCIの環境変数に設定するためメモしておきます。
$ ENV=dev make create-access-key $ ENV=prod make create-access-key
単体テスト用のファイルを作成
次のPythonコードをtest_checker.py
として作成します。
確認する内容は下記です。
- JSONファイルとして正しいか?
- 必要なKeyがあるか?
- Valueの型が期待通りか?
AssumeRole用のスクリプトを作成
AssumeRole用に次のスクリプトをassume_role.sh
として作成します。
次に実行権限を付与しておきます。
$ chmod 755 assume_role.sh
JSONファイルを作成
次のJSONファイルをinformation.json
として作成します。
CircleCIの設定ファイルを作成
.circleci
ディレクトリを作成し、その中にconfig.yml
を作成します。
$ mkdir .circleci $ touch .circleci/config.yml
続いて、config.yml
ファイルの中身を記述します。
CircleCIの設定
リポジトリのPush
まずはGitHubにリポジトリをPushしておきます。
$ git push origin master
CircleCIにログイン
CircleCIにログインします。
プロジェクト作成
「ADD PROJECT」を選択し、さきほどGitHubにPushしたリポジトリを選択します。
続いて、「Start building」を選択します。
初めてのジョブが走りますが、環境変数が未設定なので失敗します。
環境変数を設定
プロジェクト一覧の設定マークを押し、設定画面に移ります。
Environment Variables
を選択します。
次の環境変数を追加します。
Name | Value |
---|---|
AWS_ACCESS_KEY_ID_DEV | 取得したAccessKeyId(開発用) |
AWS_ACCESS_KEY_ID_PROD | 取得したAccessKeyId(本番用) |
AWS_SECRET_ACCESS_KEY_DEV | 取得したSecretAccessKey(開発用) |
AWS_SECRET_ACCESS_KEY_PROD | 取得したSecretAccessKey(本番用) |
AWS_DEPLOY_IAM_ROLE_ARN_DEV | 取得したIAMロールのARN(開発用) |
AWS_DEPLOY_IAM_ROLE_ARN_PROD | 取得したIAMロールのARN(本番用) |
AWS_DEPLOY_IAM_ROLE_EXTERNAL_ID_DEV | sts:ExternalIdで設定した値(開発用) |
AWS_DEPLOY_IAM_ROLE_EXTERNAL_ID_PROD | sts:ExternalIdで設定した値(本番用) |
AWS_DEFAULT_REGION | ap-northeast-1 |
AWS_DEFAULT_OUTPUT | json |
動作確認
開発環境
さきほど失敗したWorkflowsの「Rerun」を選択し、そこの「Rerun from failed」を選択します。
しばらくするとデプロイが成功しました!
次のコマンドでJSON取得できます。
$ curl app-information-dev.s3.amazonaws.com/information.json { "Message": "テストメッセージ", "DeadlineTimestamp": 1578636000, "Period": 86400 }
本番環境
この状態で「Approve Job」のApprove
を選択し、続いて本番環境にデプロイを進めます。
しばらく待つと、デプロイが成功しました!
次のコマンドでJSON取得できます。
$ curl app-information-prod.s3.amazonaws.com/information.json { "Message": "テストメッセージ", "DeadlineTimestamp": 1578636000, "Period": 86400 }
さいごに
思っていたよりも簡単にできました。API化は必要になったら考えたいです。